package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/hashicorp/raft"
	"log"
	"net/http"
	"os"
	"os/signal"
	"raftkv/pkg/httpd"
	"raftkv/pkg/store"
	"strings"
	"time"
)
var raftAddr string
var joinAddr string
var httpAddr string
var nodeID string
var proxyAddr string
func init(){
	flag.StringVar(&httpAddr,"haddr","127.0.0.1:8091","http 监听地址")
	flag.StringVar(&raftAddr,"raddr","127.0.0.1:8089","raft 监听地址")
	flag.StringVar(&joinAddr,"join","","单节点更改，加入主节点集群")
	flag.StringVar(&nodeID,"id","node01","节点标识")
	flag.StringVar(&proxyAddr,"proxy","http://127.0.0.1:3000","代理")
}

func main() {
	flag.Parse()
	raftDir := "F:/raftdb"

	err := os.MkdirAll(raftDir, 0700)
	if err != nil {
		log.Fatalln("create dir err")
	}

	s := store.NewStore()
	s.RaftDir = raftDir
	s.RaftBind = raftAddr
	if err = s.Open(joinAddr=="",nodeID);err!=nil{
		log.Fatalf("failed to open store: %s", err.Error())
	}
	if joinAddr!=""{
		log.Println("join in:",joinAddr)
		err = join(joinAddr,httpAddr,raftAddr,nodeID)
		if err != nil{
			log.Fatalln("join err")
		}
	}else{
		err = addProxy(nodeID,httpAddr)
	}

	openTimeout := 120 * time.Second
	s.WaitForLeader(openTimeout)
	s.WaitForLeader(openTimeout)

	if err = s.SetMeta(nodeID,httpAddr);err != nil&&err != raft.ErrNotLeader{
		log.Fatalf("failed to SetMeta at %s: %s", nodeID, err.Error())
	}
	h := httpd.NewHttpService(httpAddr,s)
	if err = h.Start();err != nil{
		log.Fatalln("failed to start Http service:",err.Error())
	}
	log.Println("raftdb started successfully")
	terminate := make(chan os.Signal,1)
	signal.Notify(terminate,os.Interrupt)
	<-terminate
	log.Fatalln("raft exiting")

}

func addProxy(nodeID,httpAddr string) error {
	params := make(map[string]interface{})
	params["serviceName"]=nodeID
	params["ip"]=httpAddr
	jsonParams, err := json.Marshal(params)
	if err!=nil{
		return err
	}
	jsonReader:= strings.NewReader(string(jsonParams))

	post, err := http.Post(proxyAddr+"/addProxy", "application/x-www-form-urlencoded", jsonReader)
	log.Println(post.StatusCode)
	if err!=nil{
		return err
	}
	return nil
}
func join(joinAddr, httpAddr, raftAddr, nodeID string) error {
	b, err := json.Marshal(map[string]string{"httpAddr": httpAddr, "raftAddr": raftAddr, "id": nodeID})
	if err != nil {
		return err
	}
	resp, err := http.Post(fmt.Sprintf("http://%s/join", joinAddr), "application-type/json", bytes.NewReader(b))
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	return nil
}
